{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# OpenVINO™ Model conversion\n",
    "\n",
    "This notebook shows how to convert a model from original framework format to OpenVINO Intermediate Representation (IR).\n",
    "\n",
    "\n",
    "#### Table of contents:\n",
    "\n",
    "- [OpenVINO IR format](#OpenVINO-IR-format)\n",
    "- [Fetching example models](#Fetching-example-models)\n",
    "- [Conversion](#Conversion)\n",
    "    - [Setting Input Shapes](#Setting-Input-Shapes)\n",
    "    - [Compressing a Model to FP16](#Compressing-a-Model-to-FP16)\n",
    "    - [Convert Models from memory](#Convert-Models-from-memory)\n",
    "- [Migration from Legacy conversion API](#Migration-from-Legacy-conversion-API)\n",
    "    - [Specifying Layout](#Specifying-Layout)\n",
    "    - [Changing Model Layout](#Changing-Model-Layout)\n",
    "    - [Specifying Mean and Scale Values](#Specifying-Mean-and-Scale-Values)\n",
    "    - [Reversing Input Channels](#Reversing-Input-Channels)\n",
    "    - [Cutting Off Parts of a Model](#Cutting-Off-Parts-of-a-Model)\n",
    "\n",
    "\n",
    "### Installation Instructions\n",
    "\n",
    "This is a self-contained example that relies solely on its own code.\n",
    "\n",
    "We recommend  running the notebook in a virtual environment. You only need a Jupyter server to start.\n",
    "For details, please refer to [Installation Guide](https://github.com/openvinotoolkit/openvino_notebooks/blob/latest/README.md#-installation-guide).\n",
    "\n",
    "<img referrerpolicy=\"no-referrer-when-downgrade\" src=\"https://static.scarf.sh/a.png?x-pxid=5b5a4db0-7875-4bfb-bdbd-01698b5b1a77&file=notebooks/convert-to-openvino/convert-to-openvino.ipynb\" />\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "from pathlib import Path\n",
    "\n",
    "if not Path(\"notebook_utils.py\").exists():\n",
    "    r = requests.get(\n",
    "        url=\"https://raw.githubusercontent.com/openvinotoolkit/openvino_notebooks/latest/utils/notebook_utils.py\",\n",
    "    )\n",
    "    open(\"notebook_utils.py\", \"w\").write(r.text)\n",
    "\n",
    "if not Path(\"pip_helper.py\").exists():\n",
    "    r = requests.get(\n",
    "        url=\"https://raw.githubusercontent.com/openvinotoolkit/openvino_notebooks/latest/utils/pip_helper.py\",\n",
    "    )\n",
    "    open(\"pip_helper.py\", \"w\").write(r.text)\n",
    "\n",
    "\n",
    "from pip_helper import pip_install\n",
    "\n",
    "pip_install(\"tensorflow==2.15.1\", \"tf_keras==2.15.1\")\n",
    "pip_install(\"--no-deps\", \"tensorflow-hub\")\n",
    "pip_install(\n",
    "    \"--extra-index-url\",\n",
    "    \"https://download.pytorch.org/whl/cpu\",\n",
    "    \"openvino>=2024.4.0\",\n",
    "    \"requests\",\n",
    "    \"tqdm\",\n",
    "    \"transformers==4.53.3\",\n",
    "    \"torch==2.8\",\n",
    "    \"torchvision\",\n",
    "    \"onnx<1.16.2\",\n",
    ")\n",
    "\n",
    "# Read more about telemetry collection at https://github.com/openvinotoolkit/openvino_notebooks?tab=readme-ov-file#-telemetry\n",
    "from notebook_utils import collect_telemetry\n",
    "\n",
    "collect_telemetry(\"convert-to-openvino.ipynb\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## OpenVINO IR format\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "OpenVINO [Intermediate Representation (IR)](https://docs.openvino.ai/2024/documentation/openvino-ir-format.html) is the proprietary model format of OpenVINO. It is produced after converting a model with model conversion API. Model conversion API translates the frequently used deep learning operations to their respective similar representation in OpenVINO and tunes them with the associated weights and biases from the trained model. The resulting IR contains two files: an `.xml` file, containing information about network topology, and a `.bin` file, containing the weights and biases binary data.\n",
    "\n",
    "There are two ways to convert a model from the original framework format to OpenVINO IR: Python conversion API and OVC command-line tool. You can choose one of them based on whichever is most convenient for you.\n",
    "\n",
    "OpenVINO conversion API supports next model formats: `PyTorch`, `TensorFlow`, `TensorFlow Lite`, `ONNX`, and `PaddlePaddle`. These model formats can be read, compiled, and converted to OpenVINO IR, either automatically or explicitly.\n",
    "\n",
    " For more details, refer to [Model Preparation](https://docs.openvino.ai/2024/openvino-workflow/model-preparation.html) documentation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# OVC CLI tool parameters description\n",
    "\n",
    "! ovc --help"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Fetching example models\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "This notebook uses two models for conversion examples:\n",
    "\n",
    "* [Distilbert](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english) NLP model from Hugging Face\n",
    "* [Resnet50](https://pytorch.org/vision/stable/models/generated/torchvision.models.resnet50.html#torchvision.models.ResNet50_Weights) CV classification model from torchvision"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pathlib import Path\n",
    "\n",
    "# create a directory for models files\n",
    "MODEL_DIRECTORY_PATH = Path(\"model\")\n",
    "MODEL_DIRECTORY_PATH.mkdir(exist_ok=True)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Fetch [distilbert](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english) NLP model from Hugging Face and export it in ONNX format:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from transformers import AutoModelForSequenceClassification, AutoTokenizer\n",
    "import torch\n",
    "\n",
    "ONNX_NLP_MODEL_PATH = MODEL_DIRECTORY_PATH / \"distilbert.onnx\"\n",
    "\n",
    "# download model\n",
    "hf_model = AutoModelForSequenceClassification.from_pretrained(\"distilbert-base-uncased-finetuned-sst-2-english\")\n",
    "# initialize tokenizer\n",
    "tokenizer = AutoTokenizer.from_pretrained(\"distilbert-base-uncased-finetuned-sst-2-english\")\n",
    "\n",
    "if not ONNX_NLP_MODEL_PATH.exists():\n",
    "    inputs = tokenizer(\"Hi, how are you?\", return_tensors=\"pt\")\n",
    "    input_names = list(inputs.keys())\n",
    "    dynamic_axes = {input_name: {0: \"batch_size\", 1: \"seq_length\"} for input_name in input_names}\n",
    "    torch.onnx.export(\n",
    "        hf_model, args=dict(inputs), input_names=input_names, output_names=[\"logits\"], dynamic_axes=dynamic_axes, f=ONNX_NLP_MODEL_PATH, opset_version=14\n",
    "    )\n",
    "    print(f\"ONNX model exported to {ONNX_NLP_MODEL_PATH}\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Fetch [Resnet50](https://pytorch.org/vision/stable/models/generated/torchvision.models.resnet50.html#torchvision.models.ResNet50_Weights) CV classification model from torchvision:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torchvision.models import resnet50, ResNet50_Weights\n",
    "\n",
    "# create model object\n",
    "pytorch_model = resnet50(weights=ResNet50_Weights.DEFAULT)\n",
    "# switch model from training to inference mode\n",
    "pytorch_model.eval()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Convert PyTorch model to ONNX format:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import warnings\n",
    "\n",
    "ONNX_CV_MODEL_PATH = MODEL_DIRECTORY_PATH / \"resnet.onnx\"\n",
    "\n",
    "if ONNX_CV_MODEL_PATH.exists():\n",
    "    print(f\"ONNX model {ONNX_CV_MODEL_PATH} already exists.\")\n",
    "else:\n",
    "    with warnings.catch_warnings():\n",
    "        warnings.filterwarnings(\"ignore\")\n",
    "        torch.onnx.export(model=pytorch_model, args=torch.randn(1, 3, 224, 224), f=ONNX_CV_MODEL_PATH)\n",
    "    print(f\"ONNX model exported to {ONNX_CV_MODEL_PATH}\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conversion\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "To convert a model to OpenVINO IR, use the following API:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import openvino as ov\n",
    "\n",
    "# ov.convert_model returns openvino.Model object\n",
    "print(ONNX_NLP_MODEL_PATH)\n",
    "ov_model = ov.convert_model(ONNX_NLP_MODEL_PATH)\n",
    "\n",
    "# then model can be serialized to *.xml & *.bin files\n",
    "ov.save_model(ov_model, MODEL_DIRECTORY_PATH / \"distilbert.xml\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! ovc model/distilbert.onnx --output_model model/distilbert.xml"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Setting Input Shapes\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "Model conversion is supported for models with dynamic input shapes that contain undefined dimensions. However, if the shape of data is not going to change from one inference request to another, it is recommended to set up static shapes (when all dimensions are fully defined) for the inputs. Doing so at the model preparation stage, not at runtime, can be beneficial in terms of performance and memory consumption.\n",
    "\n",
    "For more information refer to [Setting Input Shapes](https://docs.openvino.ai/2024/openvino-workflow/model-preparation/setting-input-shapes.html) documentation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import openvino as ov\n",
    "\n",
    "ov_model = ov.convert_model(ONNX_NLP_MODEL_PATH, input=[(\"input_ids\", [1, 128]), (\"attention_mask\", [1, 128])])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! ovc model/distilbert.onnx --input input_ids[1,128],attention_mask[1,128] --output_model model/distilbert.xml"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `input` parameter allows overriding original input shapes if it is supported by the model topology. Shapes with dynamic dimensions in the original model can be replaced with static shapes for the converted model, and vice versa. The dynamic dimension can be marked in model conversion API parameter as `-1` or `?` when using `ovc`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import openvino as ov\n",
    "\n",
    "ov_model = ov.convert_model(ONNX_NLP_MODEL_PATH, input=[(\"input_ids\", [1, -1]), (\"attention_mask\", [1, -1])])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! ovc model/distilbert.onnx --input \"input_ids[1,?],attention_mask[1,?]\" --output_model model/distilbert.xml"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To optimize memory consumption for models with undefined dimensions in runtime, model conversion API provides the capability to define boundaries of dimensions. The boundaries of undefined dimension can be specified with ellipsis in the command line or with `openvino.Dimension` class in Python. For example, launch model conversion for the ONNX Bert model and specify a boundary for the sequence length dimension:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import openvino as ov\n",
    "\n",
    "\n",
    "sequence_length_dim = ov.Dimension(10, 128)\n",
    "\n",
    "ov_model = ov.convert_model(\n",
    "    ONNX_NLP_MODEL_PATH,\n",
    "    input=[\n",
    "        (\"input_ids\", [1, sequence_length_dim]),\n",
    "        (\"attention_mask\", [1, sequence_length_dim]),\n",
    "    ],\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! ovc model/distilbert.onnx --input input_ids[1,10..128],attention_mask[1,10..128] --output_model model/distilbert.xml"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Compressing a Model to FP16\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "By default model weights compressed to FP16 format when saving OpenVINO model to IR. This saves up to 2x storage space for the model file and in most cases doesn't sacrifice model accuracy. Weight compression can be disabled by setting `compress_to_fp16` flag to `False`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import openvino as ov\n",
    "\n",
    "ov_model = ov.convert_model(ONNX_NLP_MODEL_PATH)\n",
    "ov.save_model(ov_model, MODEL_DIRECTORY_PATH / \"distilbert.xml\", compress_to_fp16=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! ovc model/distilbert.onnx --output_model model/distilbert.xml --compress_to_fp16=False"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Convert Models from memory\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "Model conversion API supports passing original framework Python object directly. More details can be found in [PyTorch](https://docs.openvino.ai/2024/openvino-workflow/model-preparation/convert-model-pytorch.html), [TensorFlow](https://docs.openvino.ai/2024/openvino-workflow/model-preparation/convert-model-tensorflow.html), [PaddlePaddle](https://docs.openvino.ai/2024/openvino-workflow/model-preparation/convert-model-paddle.html) frameworks conversion guides."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import openvino as ov\n",
    "import torch\n",
    "\n",
    "example_input = torch.rand(1, 3, 224, 224)\n",
    "\n",
    "ov_model = ov.convert_model(pytorch_model, example_input=example_input, input=example_input.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "import openvino as ov\n",
    "import tensorflow_hub as hub\n",
    "\n",
    "os.environ[\"TFHUB_CACHE_DIR\"] = str(Path(\"./tfhub_modules\").resolve())\n",
    "\n",
    "model = hub.load(\"https://www.kaggle.com/models/google/movenet/frameworks/TensorFlow2/variations/singlepose-lightning/versions/4\")\n",
    "movenet = model.signatures[\"serving_default\"]\n",
    "\n",
    "ov_model = ov.convert_model(movenet)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Migration from Legacy conversion API\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "In the 2023.1 OpenVINO release OpenVINO Model Conversion API was introduced with the corresponding Python API: `openvino.convert_model` method. `ovc` and `openvino.convert_model` represent a lightweight alternative of `mo` and `openvino.tools.mo.convert_model` which are considered legacy API now.\n",
    "`mo.convert_model()` provides a wide range of preprocessing parameters. Most of these parameters have analogs in OVC or can be replaced with functionality from `ov.PrePostProcessor` class. Refer to [Optimize Preprocessing notebook](../optimize-preprocessing/optimize-preprocessing.ipynb) for more information about [Preprocessing API](https://docs.openvino.ai/2024/openvino-workflow/running-inference/optimize-inference/optimize-preprocessing.html). Here is the migration guide from legacy model preprocessing to Preprocessing API."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Specifying Layout\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "Layout defines the meaning of dimensions in a shape and can be specified for both inputs and outputs. Some preprocessing requires to set input layouts, for example, setting a batch, applying mean or scales, and reversing input channels (BGR<->RGB). For the layout syntax, check the [Layout API overview](https://docs.openvino.ai/2024/openvino-workflow/running-inference/optimize-inference/optimize-preprocessing/layout-api-overview.html). To specify the layout, you can use the layout option followed by the layout value.\n",
    "\n",
    "The following example specifies the `NCHW` layout for a Pytorch Resnet50 model that was exported to the ONNX format:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Converter API\n",
    "import openvino as ov\n",
    "\n",
    "ov_model = ov.convert_model(ONNX_CV_MODEL_PATH)\n",
    "\n",
    "prep = ov.preprocess.PrePostProcessor(ov_model)\n",
    "prep.input(\"input.1\").model().set_layout(ov.Layout(\"nchw\"))\n",
    "ov_model = prep.build()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "# Legacy Model Optimizer API\n",
    "from openvino.tools import mo\n",
    "\n",
    "ov_model = mo.convert_model(ONNX_CV_MODEL_PATH, layout=\"nchw\")\n",
    "```"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Changing Model Layout\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "Transposing of matrices/tensors is a typical operation in Deep Learning - you may have a BMP image `640x480`, which is an array of `{480, 640, 3}` elements, but Deep Learning model can require input with shape `{1, 3, 480, 640}`.\n",
    "\n",
    "Conversion can be done implicitly, using the layout of a user’s tensor and the layout of an original model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Converter API\n",
    "import openvino as ov\n",
    "\n",
    "ov_model = ov.convert_model(ONNX_CV_MODEL_PATH)\n",
    "\n",
    "prep = ov.preprocess.PrePostProcessor(ov_model)\n",
    "prep.input(\"input.1\").tensor().set_layout(ov.Layout(\"nhwc\"))\n",
    "prep.input(\"input.1\").model().set_layout(ov.Layout(\"nchw\"))\n",
    "ov_model = prep.build()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Legacy Model Optimizer API\n",
    "```python\n",
    "from openvino.tools import mo\n",
    "\n",
    "ov_model = mo.convert_model(ONNX_CV_MODEL_PATH, layout=\"nchw->nhwc\")\n",
    "\n",
    "# alternatively use source_layout and target_layout parameters\n",
    "ov_model = mo.convert_model(ONNX_CV_MODEL_PATH, source_layout=\"nchw\", target_layout=\"nhwc\")\n",
    "```"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Specifying Mean and Scale Values\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "Using Preprocessing API `mean` and `scale` values can be set. Using these API, model embeds the corresponding preprocessing block for mean-value normalization of the input data and optimizes this block. Refer to [Optimize Preprocessing notebook](../optimize-preprocessing/optimize-preprocessing.ipynb) for more examples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Converter API\n",
    "import openvino as ov\n",
    "\n",
    "ov_model = ov.convert_model(ONNX_CV_MODEL_PATH)\n",
    "\n",
    "prep = ov.preprocess.PrePostProcessor(ov_model)\n",
    "prep.input(\"input.1\").tensor().set_layout(ov.Layout(\"nchw\"))\n",
    "prep.input(\"input.1\").preprocess().mean([255 * x for x in [0.485, 0.456, 0.406]])\n",
    "prep.input(\"input.1\").preprocess().scale([255 * x for x in [0.229, 0.224, 0.225]])\n",
    "\n",
    "ov_model = prep.build()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "# Legacy Model Optimizer API\n",
    "\n",
    "from openvino.tools import mo\n",
    "\n",
    "\n",
    "ov_model = mo.convert_model(\n",
    "    ONNX_CV_MODEL_PATH,\n",
    "    mean_values=[255 * x for x in [0.485, 0.456, 0.406]],\n",
    "    scale_values=[255 * x for x in [0.229, 0.224, 0.225]],\n",
    ")\n",
    "```"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Reversing Input Channels\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "Sometimes, input images for your application can be of the `RGB` (or `BGR`) format, and the model is trained on images of the `BGR` (or `RGB`) format, which is in the opposite order of color channels. In this case, it is important to preprocess the input images by reverting the color channels before inference."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "test_replace": {
     "ov_model = prep.build()": "ov_model = prep.build()\n%pip uninstall -q -y tensorflow tf_keras \"tensorflow-hub\" \"tensorflow-intel\" numpy"
    }
   },
   "outputs": [],
   "source": [
    "# Converter API\n",
    "import openvino as ov\n",
    "\n",
    "ov_model = ov.convert_model(ONNX_CV_MODEL_PATH)\n",
    "\n",
    "prep = ov.preprocess.PrePostProcessor(ov_model)\n",
    "prep.input(\"input.1\").tensor().set_layout(ov.Layout(\"nchw\"))\n",
    "prep.input(\"input.1\").preprocess().reverse_channels()\n",
    "ov_model = prep.build()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "# Legacy Model Optimizer API\n",
    "from openvino.tools import mo\n",
    "\n",
    "ov_model = mo.convert_model(ONNX_CV_MODEL_PATH, reverse_input_channels=True)\n",
    "```"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Cutting Off Parts of a Model\n",
    "[back to top ⬆️](#Table-of-contents:)\n",
    "\n",
    "Cutting model inputs and outputs from a model is no longer available in the new conversion API. Instead, we recommend performing the cut in the original framework. Examples of model cutting of TensorFlow protobuf, TensorFlow SavedModel, and ONNX formats with tools provided by the Tensorflow and ONNX frameworks can be found in [documentation guide](https://docs.openvino.ai/2024/documentation/legacy-features/transition-legacy-conversion-api.html#cutting-off-parts-of-a-model). For PyTorch, TensorFlow 2 Keras, and PaddlePaddle, we recommend changing the original model code to perform the model cut."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  },
  "openvino_notebooks": {
   "imageUrl": "",
   "tags": {
    "categories": [
     "Convert",
     "API Overview"
    ],
    "libraries": [],
    "other": [],
    "tasks": [
     "Image Classification",
     "Text Classification"
    ]
   }
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {},
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
